from rest_framework.response import Response
from rest_framework import status
from rest_framework.viewsets import ModelViewSet
from django.db.models.expressions import RawSQL
from django.db.models import Q, F
from django.conf import settings
import pymysql, json, datetime
from decimal import Decimal
from random import randint
from rest_framework import filters
from django_filters.rest_framework import DjangoFilterBackend
from django.db import transaction

from businesses.serializers_nfc import *
from equity_mall.utils.pages import MyPage
from businesses.filters import *
from businesses.tasks import *
from equity_mall.utils.utils import random_str, mmpaymkttransfers
from alipaynfc.utils import check_merchant_nfc_trade


class NFCDeviceBountyQuestModelViewSet(ModelViewSet):

    pagination_class = MyPage

    def get_queryset(self):
        user = self.request.iser
        longitude = self.request.query_params.get('longitude', None)
        latitude = self.request.query_params.get('latitude', None)
        sort = self.request.query_params.get('sort', None)
        today = datetime.datetime.now()
        if self.action == 'update':
            queryset = NFCDeviceBountyQuest.objects.filter(quest_status__in=[0, 1], expired_time__gte=today).exclude(nfcdevicebountyquestschedule__customeruservice__id=user.id)
        else:
            queryset = NFCDeviceBountyQuest.objects.filter(quest_status=0, expired_time__gte=today).exclude(nfcdevicebountyquestschedule__customeruservice__id=user.id)
        if self.action == 'list':
            if all([longitude, latitude]):
                gcd_formula = "6371 * acos(least(greatest(cos(radians(%s)) * cos(radians(latitude)) * cos(radians(longitude) - radians(%s)) + sin(radians(%s)) * sin(radians(latitude)) , -1), 1))"
                sql = RawSQL(gcd_formula, (latitude, longitude, latitude))
                queryset = queryset.annotate(distance=sql).order_by(F('distance').asc(nulls_last=True)) # .filter(distance__lt=5).order_by(F('distance').asc(nulls_last=True))
        if sort == '2':
            queryset = queryset.order_by('-amount')
        if sort == '1' and all([longitude, latitude]):
            queryset = queryset.order_by(F('distance').asc(nulls_last=True))
        return queryset

    def get_serializer_class(self):
        if self.action == 'list':
            return NFCDeviceBountyQuestListModelSerializer
        else:
            return NFCDeviceBountyQuestRetrieveModelSerializer

    def get_serializer_context(self):
        longitude = self.request.query_params.get('longitude', None)
        latitude = self.request.query_params.get('latitude', None)
        return {'longitude': longitude, 'latitude': latitude}

    def nfc_quest_map(self, request):
        user = self.request.iser
        longitude = self.request.query_params.get('longitude', '')
        latitude = self.request.query_params.get('latitude', '')
        distance = self.request.query_params.get('distance', 2000)
        try:
            distance = int(distance)
            distance = distance * 1.5
            if distance > 50000:
                return Response({'error': '搜索距离不能大于50公里'}, status=status.HTTP_400_BAD_REQUEST)
            distance = distance/1000
        except:
            return Response({'error': '距离参数格式有误'}, status=status.HTTP_400_BAD_REQUEST)
        if not all([latitude, longitude]):
            return Response({'error': '请上传定位经纬度'}, status=status.HTTP_400_BAD_REQUEST)
        today = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        conn = pymysql.connect(host=settings.DATABASES['default']['HOST'],
                               port=settings.DATABASES['default']['PORT'],
                               database=settings.DATABASES['default']['NAME'],
                               user=settings.DATABASES['default']['USER'],
                               password=settings.DATABASES['default']['PASSWORD'])
        cursor = conn.cursor(cursor=pymysql.cursors.SSDictCursor)
        sql = f'''SELECT a.*, b.merchant_name,merchant_short_name,store_address FROM (SELECT id,merchant_id,longitude,latitude,task_id,amount,(6371 * acos(cos(radians({latitude})) * cos(radians(latitude)) * cos( radians(longitude) - radians({longitude})) + sin(radians({latitude})) * sin(radians(latitude)))) AS distance FROM tb_nfc_device_bounty_quest WHERE quest_status=0 AND expired_time>="{today}" AND id NOT IN (SELECT quest_id FROM tb_nfc_device_bounty_quest_schedule WHERE customeruservice_id={user.id}))AS a LEFT JOIN (SELECT id,name AS merchant_name,short_name AS merchant_short_name,store_address FROM tb_merchant)AS b ON a.merchant_id=b.id;'''
        try:
            cursor.execute(sql)
            rows = cursor.fetchall()
        finally:
            cursor.close()
            conn.close()
        data = {}
        for row in rows:
            distance = row['distance']
            if distance < 1:
                row['distance'] = f'{int(distance * 1000)} m'
            else:
                row['distance'] = f'{Decimal(str(distance)).quantize(Decimal("0.00"))} km'
        data['lists'] = rows
        data['count'] = len(rows)
        return Response(data, status=status.HTTP_200_OK)

    def update(self, request, *args, **kwargs):
        user = self.request.iser
        ckeck_schedule = NFCDeviceBountyQuestSchedule.objects.filter(customeruservice_id=user.id, quest_status=1).count()
        if ckeck_schedule >= 3:
            return Response({'error': '你已经有3个任务进行中啦~请手下留情。'}, status=status.HTTP_400_BAD_REQUEST)
        instance = self.get_object()
        if instance.quest_status != 0:
            return Response({'error': '该任务已给其他赏金猎人抢走了~请查看其他任务'}, status=status.HTTP_400_BAD_REQUEST)
        today = datetime.datetime.now()
        if instance.validity_type == 1:
            expired_time = today + datetime.timedelta(minutes=instance.validity_count)
            eta = datetime.datetime.utcnow() + datetime.timedelta(minutes=instance.validity_count)
        elif instance.validity_type == 2:
            expired_time = today + datetime.timedelta(hours=instance.validity_count)
            eta = datetime.datetime.utcnow() + datetime.timedelta(hours=instance.validity_count)
        else:
            expired_time = today + datetime.timedelta(days=instance.validity_count)
            eta = datetime.datetime.utcnow() + datetime.timedelta(days=instance.validity_count)
        defaults = {}
        defaults['quest_id'] = instance.id
        defaults['create_time'] = today
        defaults['expired_time'] = expired_time
        defaults['customeruservice_id'] = user.id
        schedule, create = NFCDeviceBountyQuestSchedule.objects.get_or_create(defaults=defaults, quest_id=instance.id, customeruservice_id=user.id)
        cancel_over_time_nfc_quest.apply_async(({'schedule_id': schedule.id},), eta=eta)
        instance.quest_status = 1
        instance.save()
        return Response({'succes': '领取成功', 'id': schedule.id}, status=status.HTTP_200_OK)
    
    def accredit_subscription(self, request):
        user = self.request.iser
        longitude = self.request.data.get('longitude', None)
        latitude = self.request.data.get('latitude', None)
        if not all([latitude, longitude]):
            return Response({'error': '请上传经纬度'}, status=status.HTTP_400_BAD_REQUEST)
        data = {}
        data['customeruservice_id'] = user.id
        data['longitude'] = longitude
        data['latitude'] = latitude
        NFCDeviceBountyQuestSubscription.objects.create(**data)
        return Response({'success': '订阅成功'}, status=status.HTTP_200_OK)


class NFCDeviceBountyQuestScheduleModelViewSet(ModelViewSet):

    pagination_class = MyPage
    filter_backends = (filters.SearchFilter, DjangoFilterBackend)
    search_fields = ('name', 'wyfMerchantID', 'managerName', 'managermobile')
    filter_class = NFCDeviceBountyQuestScheduleFilter

    def get_queryset(self):
        user = self.request.iser
        queryset = NFCDeviceBountyQuestSchedule.objects.filter(customeruservice_id=user.id)
        return queryset.order_by('-id')

    def get_serializer_class(self):
        if self.action == 'list':
            return NFCDeviceBountyQuestScheduleListModelSerializer
        else:
            return NFCDeviceBountyQuestScheduleRetrieveModelSerializer

    def get_serializer_context(self):
        longitude = self.request.query_params.get('longitude', None)
        latitude = self.request.query_params.get('latitude', None)
        return {'longitude': longitude, 'latitude': latitude}

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        appeal_explain = self.request.data.get('appeal_explain', None)
        assist_arr = self.request.data.get('assist_arr', None)
        if instance.quest_status != 1:
            return Response({'error': '任务状态有误'}, status=status.HTTP_400_BAD_REQUEST)
        if not all([appeal_explain, assist_arr]):
            return Response({'error': '请上传申诉材料跟原因'}, status=status.HTTP_400_BAD_REQUEST)
        instance.appeal_explain = appeal_explain
        instance.appeal_time = datetime.datetime.now()
        instance.quest_status = 3
        instance.save()
        quest = instance.quest
        quest.quest_status = 3
        quest.save()
        for assist in assist_arr:
            NFCDeviceBountyQuestScheduleAppealAssist.objects.create(schedule_id=instance.id, picture=assist)
        return Response({'success': '提交申诉成功,请等待客服核实'}, status=status.HTTP_200_OK)

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        if instance.quest_status != 1:
            return Response({'error': '任务状态有误'}, status=status.HTTP_400_BAD_REQUEST)
        instance.quest_status = 4
        instance.cancel_time = datetime.datetime.now()
        instance.save()
        quest = instance.quest
        quest.quest_status = 0
        quest.save()
        return Response({'success': '取消成功'}, status=status.HTTP_200_OK)

    def partial_update(self, request, *args, **kwargs):
        instance = self.get_object()
        user = self.request.iser
        if instance.quest_status != 1:
            return Response({'error': '任务状态有误'}, status=status.HTTP_400_BAD_REQUEST)
        quest = instance.quest
        # if user.id not in [3073523, 2707851]:
        #     return Response({'error': '任务尚未完成'}, status=status.HTTP_400_BAD_REQUEST)
        # else:
        business_no = quest.merchant.wyfMerchantID
        create_time = instance.create_time.strftime("%Y-%m-%d %H:%M:%S")
        expired_time = instance.expired_time.strftime("%Y-%m-%d %H:%M:%S")
        result = check_merchant_nfc_trade(business_no, create_time, expired_time)
        if result == 0:
            return Response({'error': '任务尚未完成'}, status=status.HTTP_400_BAD_REQUEST)
        activity = CashActivity.objects.get(id=1028)
        amount = quest.amount
        date_now = datetime.datetime.now()
        with transaction.atomic():
            save_id = transaction.savepoint()
            try:
                activity_id = activity.id
                while True:
                    activity = CashActivity.objects.get(id=activity_id)
                    activity_origin_take_amount = activity.take_amount
                    activity_origin_remain_amount = activity.remain_amount
                    if activity_origin_remain_amount < amount:
                        transaction.savepoint_rollback(save_id)
                        return Response({'error': '活动已达到派发上限'}, status=status.HTTP_400_BAD_REQUEST)
                    activity_new_take_amount = activity_origin_take_amount + amount
                    activity_new_remain_amount = activity_origin_remain_amount - amount
                    result = CashActivity.objects.filter(take_amount=activity_origin_take_amount, remain_amount=activity_origin_remain_amount, id=activity_id).update(
                        take_amount=activity_new_take_amount, remain_amount=activity_new_remain_amount)
                    if result == 0:
                        continue
                    break
                activity_data = {}
                activity_data['amount'] = amount
                activity_data['create_time'] = date_now
                activity_data['cash_activity_id'] = activity.id
                activity_data['state'] = 1
                activity_data['customeruservice_id'] = user.id
                identify = random_str()
                nonce_str = random_str()
                activity_data['identify'] = identify
                activity_data['nonce_str'] = nonce_str
                activity_data['desc'] = activity.name
                activity_data['partner_trade_no'] = f'{date_now.strftime("%Y%m%d%H%M%S")}{"%06d" % randint(0, 999999)}{"%06d" % user.id}'
                activity_data['expired_time'] = date_now + datetime.timedelta(hours=11)
                activity_dat, create = CashActivityData.objects.get_or_create(defaults=activity_data, identify=identify)
                instance.award_id = activity_dat.id
                instance.quest_status = 2
                instance.success_time = date_now
                instance.save()
                quest = instance.quest
                quest.quest_status = 2
                quest.save()
            except:
                transaction.savepoint_rollback(save_id)
                return Response({'error': '系统繁忙,请刷新重试'}, status=status.HTTP_400_BAD_REQUEST)
        transaction.savepoint_commit(save_id)
        return Response({'success': '操作成功', "award_id": activity_dat.id}, status=status.HTTP_200_OK)
        # return Response({'error': '任务尚未完成'}, status=status.HTTP_400_BAD_REQUEST)

    def draw_down_quest(self, reqeust):
        user = self.request.iser
        award_id = self.request.data.get('award_id', None)
        if not award_id:
            return Response({'error': '缺少必传参数'}, status=status.HTTP_400_BAD_REQUEST)
        try:
            cashactivitydata = CashActivityData.objects.get(id=award_id)
        except:
            return Response({'error': '无效领奖参数'}, status=status.HTTP_400_BAD_REQUEST)
        if cashactivitydata.state != 1:
            return Response({'error': '奖励状态有误'}, status=status.HTTP_400_BAD_REQUEST)
        if cashactivitydata.customeruservice_id != user.id:
            return Response({'error': '您无权限领取'}, status=status.HTTP_400_BAD_REQUEST)
        date_now = datetime.datetime.now()
        cash_activity_id = cashactivitydata.cash_activity_id
        cashactivity = cashactivitydata.cash_activity
        if cashactivity.available_end_time <= date_now:
            return Response({'error': '活动已结束', 'status': ''}, status=status.HTTP_400_BAD_REQUEST)
        appid = settings.CUSTOMER_APP_ID_WYH
        openid = user.wyh_openid
        today_time_begin = date_now.strftime('%Y-%m-%d 00:00:00')
        today_time_end = date_now.strftime('%Y-%m-%d 23:59:59')
        encouragedraw = CashActivityData.objects.filter(received_time__gte=today_time_begin, received_time__lte=today_time_end, return_msg__contains='已达到今日商户付款额度上限')
        if encouragedraw:
            return Response({'error': '微信额度已达到今日上限,请明日领取'}, status=status.HTTP_400_BAD_REQUEST)
        encouragedraw_set = CashActivityData.objects.filter(received_time__gte=today_time_begin, received_time__lte=today_time_end, customeruservice_id=user.id, state=2)
        today_amount = Decimal('0')
        for encouragedraw in encouragedraw_set:
            today_amount += encouragedraw.amount
        today_amount += cashactivitydata.amount
        if today_amount > Decimal('500'):
            return Response({'error': '微信额度已达到今日上限,请明日领取', 'status': ''}, status=status.HTTP_400_BAD_REQUEST)
        else:
            cashactivitydata.state = 5
            cashactivitydata.channel_id = cashactivity.wx_channel_id
            cashactivitydata.save()
            mchid = '1486198522'
            params = {
                'mch_appid': appid,
                'mchid': '1486198522',  # 商户号
                'nonce_str': cashactivitydata.nonce_str,
                'partner_trade_no': cashactivitydata.partner_trade_no,
                'openid': openid,
                'check_name': 'NO_CHECK',
                'amount': int(cashactivitydata.amount * 100),
                'desc': cashactivitydata.desc
            }
            data_dict = mmpaymkttransfers(params)
            if data_dict['result_code'] == 'SUCCESS':
                cashactivitydata.state = 2
                cashactivitydata.received_time = data_dict['payment_time']
                cashactivitydata.payment_no = data_dict['payment_no']
                cashactivitydata.mchid = mchid
                cashactivitydata.mobile = user.mobile
                cashactivitydata.save()
                while True:
                    activity = CashActivity.objects.get(id=cash_activity_id)
                    origin_distributed_amount = activity.distributed_amount
                    new_distributed_amount = origin_distributed_amount + cashactivitydata.amount
                    result = CashActivity.objects.filter(id=cash_activity_id, distributed_amount=origin_distributed_amount).update(distributed_amount=new_distributed_amount)
                    if result == 0:
                        continue
                    break
                return Response({'success': '领取成功'}, status=status.HTTP_200_OK)
            else:
                cashactivitydata.return_msg = data_dict['err_code_des']
                cashactivitydata.state = 3
                cashactivitydata.received_time = date_now
                cashactivitydata.customeruservice_id = user.id
                cashactivitydata.mchid = mchid
                cashactivitydata.mobile = user.mobile
                cashactivitydata.save()
                return Response({'error': f'领取失败,{data_dict["err_code_des"]}'}, status=status.HTTP_400_BAD_REQUEST)

    def underway_quest_count(self, request):
        ing_count = self.get_queryset().filter(quest_status=1).count()
        data = {}
        data['ing_count'] = ing_count
        return Response(data, status=status.HTTP_200_OK)





